"""Configuration management for model adapters."""

import os
import json
from typing import Dict, Any, Optional, List
from dataclasses import asdict
from cryptography.fernet import Fernet
from pathlib import Path

from .base import ModelConfig, ModelType


class ConfigManager:
    """Manages model configurations with encryption and validation."""
    
    def __init__(self, config_path: str = None):
        """Initialize configuration manager.
        
        Args:
            config_path: Path to configuration file
        """
        self.config_path = config_path or os.getenv("MODEL_CONFIG_PATH", "config/models.json")
        self._configs: Dict[str, ModelConfig] = {}
        self._cipher = self._init_cipher()
        self._load_configs()
    
    def _init_cipher(self) -> Fernet:
        """Initialize encryption cipher.
        
        Returns:
            Fernet cipher for encryption/decryption
        """
        # Get or generate encryption key
        key_path = Path(".keys/model_config.key")
        
        if key_path.exists():
            with open(key_path, "rb") as f:
                key = f.read()
        else:
            # Generate new key
            key = Fernet.generate_key()
            key_path.parent.mkdir(parents=True, exist_ok=True)
            with open(key_path, "wb") as f:
                f.write(key)
            # Set restrictive permissions
            os.chmod(key_path, 0o600)
        
        return Fernet(key)
    
    def _encrypt_value(self, value: str) -> str:
        """Encrypt sensitive value.
        
        Args:
            value: Plain text value
            
        Returns:
            Encrypted value as string
        """
        return self._cipher.encrypt(value.encode()).decode()
    
    def _decrypt_value(self, value: str) -> str:
        """Decrypt sensitive value.
        
        Args:
            value: Encrypted value
            
        Returns:
            Decrypted plain text
        """
        return self._cipher.decrypt(value.encode()).decode()
    
    def _load_configs(self) -> None:
        """Load configurations from file and environment."""
        # Load from file if exists
        if os.path.exists(self.config_path):
            with open(self.config_path, "r") as f:
                data = json.load(f)
                for model_name, config_data in data.items():
                    # Decrypt API keys
                    if "api_key" in config_data and config_data["api_key"]:
                        if config_data["api_key"].startswith("enc:"):
                            config_data["api_key"] = self._decrypt_value(
                                config_data["api_key"][4:]
                            )
                    self._configs[model_name] = ModelConfig(**config_data)
        
        # Override with environment variables
        self._load_env_configs()
    
    def _load_env_configs(self) -> None:
        """Load configurations from environment variables."""
        env_mapping = {
            "OPENAI_API_KEY": ("gpt-4", "api_key"),
            "OPENAI_API_BASE": ("gpt-4", "api_base"),
            "ANTHROPIC_API_KEY": ("claude-3", "api_key"),
            "QWEN_API_KEY": ("qwen-max", "api_key"),
            "WENXIN_API_KEY": ("ernie-bot-4", "api_key"),
            "WENXIN_SECRET_KEY": ("ernie-bot-4", "extra_params.secret_key"),
        }
        
        for env_var, (model_name, config_path) in env_mapping.items():
            value = os.getenv(env_var)
            if value:
                if model_name not in self._configs:
                    self._configs[model_name] = ModelConfig(model_name=model_name)
                
                # Handle nested paths
                if "." in config_path:
                    parts = config_path.split(".")
                    if parts[0] == "extra_params":
                        self._configs[model_name].extra_params[parts[1]] = value
                else:
                    setattr(self._configs[model_name], config_path, value)
    
    def get_config(self, model_name: str) -> Optional[ModelConfig]:
        """Get configuration for a model.
        
        Args:
            model_name: Name of the model
            
        Returns:
            ModelConfig or None if not found
        """
        return self._configs.get(model_name)
    
    def set_config(self, model_name: str, config: ModelConfig) -> None:
        """Set configuration for a model.
        
        Args:
            model_name: Name of the model
            config: Model configuration
        """
        config.validate()
        self._configs[model_name] = config
        self._save_configs()
    
    def update_config(self, model_name: str, **kwargs) -> None:
        """Update specific configuration parameters.
        
        Args:
            model_name: Name of the model
            **kwargs: Configuration parameters to update
        """
        if model_name not in self._configs:
            self._configs[model_name] = ModelConfig(model_name=model_name)
        
        config = self._configs[model_name]
        for key, value in kwargs.items():
            if hasattr(config, key):
                setattr(config, key, value)
            elif key in ["extra_params"]:
                config.extra_params.update(value)
        
        config.validate()
        self._save_configs()
    
    def _save_configs(self) -> None:
        """Save configurations to file with encryption."""
        data = {}
        for model_name, config in self._configs.items():
            config_dict = asdict(config)
            # Encrypt API keys
            if config_dict.get("api_key"):
                config_dict["api_key"] = "enc:" + self._encrypt_value(config_dict["api_key"])
            data[model_name] = config_dict
        
        # Ensure directory exists
        Path(self.config_path).parent.mkdir(parents=True, exist_ok=True)
        
        with open(self.config_path, "w") as f:
            json.dump(data, f, indent=2)
    
    def list_configs(self) -> List[str]:
        """List available model configurations.
        
        Returns:
            List of configured model names
        """
        return list(self._configs.keys())
    
    def validate_config(self, model_name: str) -> bool:
        """Validate a model configuration.
        
        Args:
            model_name: Name of the model
            
        Returns:
            True if valid, False otherwise
        """
        config = self.get_config(model_name)
        if not config:
            return False
        
        try:
            config.validate()
            return True
        except ValueError:
            return False
    
    def get_all_configs(self) -> Dict[str, ModelConfig]:
        """Get all configurations.
        
        Returns:
            Dictionary of all model configurations
        """
        return self._configs.copy()
    
    async def health_check_all(self) -> Dict[str, bool]:
        """Check health of all configured models.
        
        Returns:
            Dictionary of model health status
        """
        results = {}
        for model_name in self._configs:
            # This would instantiate adapter and check
            # For now, just validate config
            results[model_name] = self.validate_config(model_name)
        return results
    
    def reload_configs(self) -> None:
        """Reload configurations from file and environment."""
        self._configs.clear()
        self._load_configs()